import com.intellij.database.model.DasTable
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

import java.text.SimpleDateFormat
import java.util.Map
import java.util.HashMap

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

author = "majie";
pkIdText = "\u4e3b\u952eID";//约定含有“主键ID”的文本注释列为主键
logicText = "\u903b\u8f91\u5220\u9664";//约定含有逻辑删除的文本列为逻辑删除字段

dateTime = getDateTime();
typeMapping = [
        (~/(?i)bigint/)                   : "Long",
        (~/(?i)int/)                      : "Integer",
        (~/(?i)float|double|decimal|real/): "Double",
        (~/(?i)tinyint/)                  : "Boolean",
        (~/(?i)datetime|timestamp|date/)  : "LocalDateTime",
        (~/(?i)blob|binary|bfile|clob|raw|image/): "InputStream",
        (~/(?i)/)                         : "String"
]

def getPackageName(dir , suffix) {
    return dir.toString().replaceAll("\\\\", ".").replaceAll("/", ".")
            .replaceAll("^.*src(\\.main\\.java\\.)?", "") + suffix
}

def getDateTime(){
    return new SimpleDateFormat("yyyy/MM/dd HH:mm").format(new Date());
}

def getImportMapping(type){
    Map<String , String> map = new HashMap();
//    map.put("LocalDateTime" , "java.time.LocalDateTime")
    map.put("InputStream" , "java.io.InputStream")
    if(map.containsKey(type)){
        return map.get(type)
    }
    return type
}

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
    SELECTION.filter { it instanceof DasTable }.each { generate(it, dir) }
}

def generate(table, dir) {
    def className = javaName(table.getName(), true)
    def fields = calcFields(table)
    //生成Model 实体类
    generateModel(table , dir , className , fields);
    //生成Mapper 接口类
//    generateMapper(table , dir , className);
//    //生成Service 接口类
//    generateServiceInterface(table , dir , className);
//    //生成Service 实现类
//    generateServiceClass(table , dir , className);
    //生成Controller 控制类
//    generateController(table , dir , className);
}

def generateModel(table , dir , className , fields){
    String parent = new File(dir.toString()).getPath();
    File folder = new File(parent + "/entity");
    File evtFolder = new File(parent + "/evt");
    File voFolder = new File(parent + "/vo");
    if (!folder.exists()) folder.mkdirs();
    if (!evtFolder.exists()) evtFolder.mkdirs();
    if (!voFolder.exists()) voFolder.mkdirs();
    new File(folder , className + "Entity.java").withPrintWriter("UTF-8") { out -> generateModelImpl(dir , table , out, className, fields) }
}

/**
 * 生成的时候，选择项目的代码路径，从包路径中找src/java/main路径后的路径开始替换
 */
def generateModelImpl(dir, table, out, className, fields) {
    def packageName = getPackageName(dir , ".entity;");
    tableName = table.getName();
    out.println "package $packageName"
    out.println ""
    //约定按照列的描述中含有主键ID的字段备注为主键，某些关系表中的第一个字段不一定就是主键
    modelExistPk(fields , out);
    out.println "import com.baomidou.mybatisplus.annotation.TableField;"
    out.println "import com.baomidou.mybatisplus.annotation.TableName;"
    out.println "import com.fasterxml.jackson.annotation.JsonFormat;"

    out.println "import com.baomidou.mybatisplus.annotation.*;"
    modelExistLogic(fields , out);
    out.println "import lombok.Data;"
    out.println "import java.time.LocalDateTime;"
    out.println "/**"
    out.println " * " + table.getComment()
    out.println " * @author $author"
    out.println " * @date $dateTime"
    out.println " */"
    out.println "@Data"
    out.println "@TableName(\"$tableName\")"
    out.println "public class $className"+"Entity {"
    out.println ""
    fields.each() {
        out.println "    // ${it.comment}"
        if (it.annos != "") out.println "  ${it.annos}"
        if (it.comment.indexOf(pkIdText) != -1){
            out.println "    @TableId(value = \"${it.tname}\" , type = IdType.ASSIGN_ID)"
        } else if (it.comment.indexOf(logicText) != -1){
            out.println "    @TableField(value=\"${it.tname}\")"
            out.println "    @TableLogic"
            out.println "    @JsonIgnore"
        } else {
            if(it.tname=="gmt_create"){
                out.println "    @TableField(value=\"${it.tname}\",fill = FieldFill.INSERT )"
            }else if(it.tname=="gmt_modified"){
                out.println "    @TableField(value=\"${it.tname}\" ,fill = FieldFill.INSERT_UPDATE)"
            }else {
                out.println "    @TableField(value=\"${it.tname}\" )"
            }

        }
        if(it.tname=="status"){
            out.println "    @TableLogic(delval = \"D\" ,value=\"E\")"
        }

        if(getImportMapping(it.type)=="LocalDateTime"){
            out.println "     @JsonFormat(pattern=\"yyyy-MM-dd HH:mm:ss\",timezone=\"GMT+8\")"
        }

        out.println "    private " + getImportMapping(it.type) + " ${it.name};"
        out.println ""
    }
    out.println "}"
}

def calcFields(table) {
    DasUtil.getColumns(table).reduce([]) { fields, col ->
        def spec = Case.LOWER.apply(col.getDataType().getSpecification())
        def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
        fields += [[
                           tname :col.getName(),
                           name : javaName(col.getName(), false), //表字段名称转为Java命名
                           type : typeStr, //表字段类型
                           comment: col.getComment() == null ? "" : col.getComment(), //表字段注释
                           annos: ""]]
    }
}

def javaName(str, capitalize) {
    def s = com.intellij.psi.codeStyle.NameUtil.splitNameIntoWords(str.minus("tf_"))
            .collect { Case.LOWER.apply(it).capitalize() }
            .join("")
            .replaceAll(/[^\p{javaJavaIdentifierPart}[_]]/, "_")
    capitalize || s.length() == 1? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def modelExistPk(fields , out){
    fields.each() {
        if (it.comment.indexOf(pkIdText) != -1){
            out.println "import com.baomidou.mybatisplus.annotation.IdType;"
            out.println "import com.baomidou.mybatisplus.annotation.TableId;"
        }

    }
}

def modelExistLogic(fields , out){
    fields.each() {
        if (it.comment.indexOf(logicText) != -1){
            out.println "import com.baomidou.mybatisplus.annotation.TableLogic;"
            out.println "import com.fasterxml.jackson.annotation.JsonIgnore;"
        }

    }
}

//------------创建Mapper
def generateMapper(table , dir , className){
    String parent = new File(dir.toString()).getPath();
    File folder = new File(parent + "/mapper");
    if (!folder.exists()) folder.mkdirs();
    new File(folder , className + "Mapper.java").withPrintWriter("UTF-8") { out -> generateMapperImpl(table , dir , out, className) }
}

def generateMapperImpl(table , dir , out , className) {
    def packageName = getPackageName(dir , "");
    out.println "package $packageName" + ".mapper;"
    out.println ""
    out.println "import com.baomidou.mybatisplus.core.mapper.BaseMapper;"
    out.println "import $packageName" + ".entity." + className + "Entity;"
    out.println ""
    out.println "/**"
    out.println " * " + table.getComment() + "Mapper\u63a5\u53e3\u5b9a\u4e49"
    out.println " * @author $author"
    out.println " * @date $dateTime"
    out.println " */"
    out.println "public interface $className" + "Mapper extends BaseMapper<$className"+"Entity> {"
    out.println ""
    out.println "    "
    out.println "}"
}

//------------创建Service接口
def generateServiceInterface(table , dir , className){
    String parent = new File(dir.toString()).getPath();
    File folder = new File(parent + "/service");
    if (!folder.exists()) folder.mkdirs();
    new File(folder , "I" + className + "Service.java").withPrintWriter("UTF-8") { out -> generateServiceInterfaceImpl(table , dir , out, className) }
}

def generateServiceInterfaceImpl(table , dir , out , className) {
    def packageName = getPackageName(dir , "");
    out.println "package $packageName" + ".service;"
    out.println ""
    out.println "import $packageName" + ".entity." + className +"Entity;"
    out.println "import com.baomidou.mybatisplus.extension.service.IService;"
    out.println ""
    out.println "/**"
    out.println " * " + table.getComment() + "Service\u63a5\u53e3\u5b9a\u4e49"
    out.println " * @author $author"
    out.println " * @date $dateTime"
    out.println " */"
    out.println "public interface I$className" + "Service extends IService<$className"+"Entity>  {"
    out.println ""
    out.println "    "
    out.println "}"

}

//------------创建Service实现类
def generateServiceClass(table , dir , className){
    String parent = new File(dir.toString()).getPath();
    File folder = new File(parent + "/service/impl");
    if (!folder.exists()) folder.mkdirs();
    new File(folder , className + "Service.java").withPrintWriter("UTF-8") { out -> generateServiceClassImpl(table , dir , out, className) }
}

def generateServiceClassImpl(table , dir , out, className) {
    def packageName = getPackageName(dir , "");
    out.println "package $packageName" + ".service.impl;"
    out.println ""
    out.println "import $packageName" + ".entity." + "$className"+"Entity;"
    out.println "import $packageName" + ".mapper." + "$className" + "Mapper;"
    out.println "import $packageName" + ".service." + "I$className" + "Service;"
    out.println "import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;"
    out.println "import org.springframework.stereotype.Service;"
    out.println "import javax.annotation.Resource;"
    out.println ""
    out.println "/**"
    out.println " * " + table.getComment() + "Service\u63a5\u53e3\u5b9e\u73b0"
    out.println " * @author $author"
    out.println " * @date $dateTime"
    out.println " */"
    out.println "@Service"
    out.println "public class $className" + "Service extends ServiceImpl<$className" + "Mapper , $className"+"Entity> implements I$className" + "Service {"
    out.println ""
    out.println "    @Resource"
    out.println "    private $className" + "Mapper " + className.uncapitalize() + "Mapper;"
    out.println ""
    out.println "}"
}

//------------创建Controller控制类
def generateController(table , dir , className) {
    String parent = new File(dir.toString()).getPath();
    File folder = new File(parent + "/controller");
    if (!folder.exists()) folder.mkdirs();
    new File(folder , className + "Controller.java").withPrintWriter("UTF-8") { out -> generateControllerImpl(table , dir , out, className) }
}

def generateControllerImpl(table , dir , out, className) {
    def packageName = getPackageName(dir , "");
    out.println "package $packageName" + ".controller;"
    out.println ""
    out.println "import $packageName" + ".service." + "I$className" + "Service;"
    out.println "import javax.annotation.Resource;"
    out.println "import io.swagger.annotations.Api;"
    out.println "import com.github.xiaoymin.knife4j.annotations.ApiSort;"
    out.println "import org.springframework.web.bind.annotation.RestController;"
    out.println "import org.springframework.web.bind.annotation.RequestMapping;"
    out.println "import org.springframework.http.MediaType;"
    out.println ""
    out.println "/**"
    out.println " * " + table.getComment() + "Controller\u63a5\u53e3\u5b9a\u4e49"
    out.println " * @author $author"
    out.println " * @date $dateTime"
    out.println " */"
    out.println "@Api(value = \"" + table.getComment() + "\" , tags = \"" + table.getComment() + "\")"
    out.println "@ApiSort(10)"
    out.println "@RequestMapping(value = \"\" , produces = MediaType.APPLICATION_JSON_VALUE)"
    out.println "@RestController"
    out.println "public class $className" + "Controller  {"
    out.println ""
    out.println "    @Resource"
    out.println "    private I$className" + "Service " + className.uncapitalize() + "Service;"
    out.println ""
    out.println "}"
}